package node.func;

import grammar.Lexer;
import grammar.MyError;
import lexical.Key;
import lexical.Word;
import midcode.MidCode;
import midcode.MidcodeGenerator;
import midcode.OPType;
import node.Node;
import node.exp.Exp;
import node.func.param.FuncRParams;
import symbol.Function;
import symbol.SymbolTable;

import java.util.ArrayList;
import java.util.Objects;

public class FuncCall implements Node {
    private final Lexer lexer;
    private final SymbolTable table;
    private final Node father;
    private Function function;
    private FuncRParams funcRParams;
    private ArrayList<Node> nodes = new ArrayList<>();

    public FuncCall(Lexer lexer, SymbolTable table, Node father) {
        this.lexer = lexer;
        this.table = table;
        this.father = father;
        parseFuncCall();
    }

    private void parseFuncCall() {
        Word word = lexer.getWord(0);
        function = table.getFunction(word.word);
        if (function == null) {
            lexer.addError(new MyError(word.lineNum, 'c')); //error c
        }
        nodes.add(lexer.getCurWord()); // ident
        nodes.add(lexer.getCurWord()); // (
        if (!lexer.isWordType(0, Key.RPARENT) && !lexer.isWordType(0, Key.SEMICN)) {
            funcRParams = new FuncRParams(lexer, table, this, function, word.lineNum);
            nodes.add(funcRParams);
        }
        if (lexer.isWordType(0, Key.RPARENT)) {
            nodes.add(lexer.getCurWord()); // )
        } else {
            lexer.addError(new MyError(lexer.getWord(-1).lineNum, 'j'));
        }
    }

    @Override
    public Node getFather() {
        return null;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        for (Node n : nodes) {
            sb.append(n.toString());
        }
        return sb.toString();
    }

    @Override
    public String genMidCode() {
        MidcodeGenerator mg = MidcodeGenerator.getInstance();
        mg.addMidcode(new MidCode(OPType.PRE_CALL, null, null, function.getName()));
        if (funcRParams != null) {
            funcRParams.genMidCode();
        }
        mg.addMidcode(new MidCode(OPType.CALL, null, null, function.getName()));
        mg.addMidcode(new MidCode(OPType.FIN_CALL, null, null, function.getName()));
        if (Objects.equals(function.returnType, "int")) {
            String tmp = mg.genTmp();
            mg.addMidcode(new MidCode(OPType.GET_RET, null, null, tmp));
            return tmp;
        }
        return "";
    }
}

